home *** CD-ROM | disk | FTP | other *** search
/ SGI Developer Toolbox 6.1 / SGI Developer Toolbox 6.1 - Disc 4.iso / src / exampleCode / inventor / SpaceballViewer / MyColEd.c++ < prev    next >
Encoding:
C/C++ Source or Header  |  1994-08-02  |  45.7 KB  |  1,709 lines

  1. /*
  2.  * Copyright (c) 1990-1991, 1994 Silicon Graphics, Inc.
  3.  *
  4.  * Permission to use, copy, modify, distribute, and sell this software and
  5.  * its documentation for any purpose is hereby granted without fee, provided
  6.  * that the name of Silicon Graphics may not be used in any advertising or
  7.  * publicity relating to the software without the specific, prior written
  8.  * permission of Silicon Graphics.
  9.  *
  10.  * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND,
  11.  * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
  12.  * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
  13.  *
  14.  * IN NO EVENT SHALL SILICON GRAPHICS BE LIABLE FOR ANY SPECIAL, INCIDENTAL,
  15.  * INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, OR ANY DAMAGES WHATSOEVER
  16.  * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER OR NOT ADVISED OF THE
  17.  * POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF LIABILITY, ARISING OUT OF OR IN
  18.  * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  19.  */
  20. /*
  21.  * Copyright (C) 1990,91   Silicon Graphics, Inc.
  22.  *
  23.  _______________________________________________________________________
  24.  ______________  S I L I C O N   G R A P H I C S   I N C .  ____________
  25.  |
  26.  |   $Revision: 1.1020 $
  27.  |
  28.  |   Classes:
  29.  |    MyColorEditor
  30.  |
  31.  |   Author(s)    : Alain Dumesny
  32.  |
  33.  |
  34.  ______________  S I L I C O N   G R A P H I C S   I N C .  ____________
  35.  _______________________________________________________________________
  36.  */
  37.  
  38. /*
  39.  * Includes
  40.  */
  41.  
  42. #include <X11/StringDefs.h>
  43. #include <X11/Intrinsic.h>
  44. #include <Xm/Xm.h>
  45. #include <Xm/Form.h>
  46. #include <Xm/RowColumn.h>
  47. #include <Xm/PushB.h>
  48. #include <Xm/PushBG.h>
  49. #include <Xm/CascadeB.h>
  50. #include <Xm/CascadeBG.h>
  51. #include <Xm/BulletinB.h>
  52. #include <Xm/Separator.h>
  53. #include <Xm/SeparatoG.h>
  54. #include <Xm/ToggleB.h>
  55. #include <Xm/ToggleBG.h>
  56.  
  57. #include <Inventor/actions/SoSearchAction.h>
  58. #include <Inventor/SoLists.h>
  59. #include <Inventor/SoPath.h>
  60. #include <Inventor/sensors/SoNodeSensor.h>
  61. #include <Inventor/fields/SoMFColor.h>
  62. #include <Inventor/fields/SoSFColor.h>
  63. #include <Inventor/nodes/SoBaseColor.h>
  64. #include <Inventor/nodes/SoMaterial.h>
  65. #include <Inventor/Xt/SoXt.h>
  66. #include <Inventor/Xt/SoXtResource.h>
  67. #include <Inventor/Xt/SoXtClipboard.h>
  68. #include <Inventor/errors/SoDebugError.h>
  69. #include "MyColorPatch.h"
  70. #include "MyColorEditor.h"
  71. #include "MyColorSlider.h"
  72. #include "MyColorWheel.h"
  73.  
  74. /*
  75.  * Defines
  76.  */
  77.  
  78. // default window sizes, and layout positions
  79. #define DEFAULT_WIDTH             280
  80. #define DEFAULT_HEIGHT             170
  81. #define TOP_REGION_SIZE                    4.1   // size of the upper half in sliders number
  82. #define BUTTONS_FORM_RIGHT_POSITION    50
  83. // pixels offset used for placing things
  84. #define OFFSET                            5
  85.  
  86. // ID list for all parts of the color editor
  87. enum {
  88.     R_SLIDER_ID = 0,    // convenient to have it start a 0
  89.     G_SLIDER_ID, 
  90.     B_SLIDER_ID, 
  91.     H_SLIDER_ID, 
  92.     S_SLIDER_ID, 
  93.     V_SLIDER_ID,
  94.     COLOR_WHEEL_ID, 
  95.     SAVE_ID, 
  96.     SWAP_ID, 
  97.     RESTORE_ID,
  98.     ACCEPT_ID,
  99.     CONTINUOUS_ID,
  100.     MANUAL_ID,
  101.     NONE_SLIDER_ID, 
  102.     INTENSITY_SLIDER_ID, 
  103.     RGB_SLIDERS_ID, 
  104.     HSV_SLIDERS_ID, 
  105.     RGB_V_SLIDERS_ID, 
  106.     RGB_HSV_SLIDERS_ID, 
  107.     WYSIWYG_ID, 
  108.     COPY_ID, 
  109.     PASTE_ID, 
  110.     HELP_ID, 
  111.     NUM_IDS,    // this must be last
  112. };
  113.  
  114. // the menu items which toggle
  115. enum {
  116.     CONTINUOUS_TOGGLE = 0,     // convenient to start at 0
  117.     ACCEPT_TOGGLE, 
  118.     WYSIWYG_TOGGLE, 
  119.     NONE_TOGGLE, 
  120.     INTENSITY_TOGGLE, 
  121.     RGB_TOGGLE, 
  122.     HSV_TOGGLE, 
  123.     RGB_V_TOGGLE, 
  124.     RGB_HSV_TOGGLE, 
  125.     NUM_TOGGLES,      // this must be last
  126. };
  127.  
  128. #define TOGGLE_ON(BUTTON) \
  129.     XmToggleButtonSetState((Widget) BUTTON, TRUE, FALSE)
  130. #define TOGGLE_OFF(BUTTON) \
  131.     XmToggleButtonSetState((Widget) BUTTON, FALSE, FALSE)
  132.  
  133. //
  134. // struct used for internal callbacks
  135. //
  136. typedef struct ColorEditorCBData {
  137.     short   id;
  138.     class MyColorEditor    *classPtr;
  139. };
  140.  
  141.  
  142.  
  143. /*
  144.  * Globals vars
  145.  */
  146.  
  147. // strings used in motif buttons/menus
  148. static char *slider_labels[] = { "R", "G", "B", "H", "S", "V"};
  149. static char *button_names[] = { "right", "switch", "left"};
  150. static char *edit_menu[] = { "Continuous", "Manual", 
  151.                             "sep", "WYSIWYG",
  152.                 "sep", "Copy", "Paste", 
  153.                 "sep", "Help"};
  154. static char *slider_menu[] = { "None", "Value", "RGB", "HSV", 
  155.                 "RGB V", "RGB HSV"};
  156.  
  157. // arrow pointing to the right
  158. #define right_width 24
  159. #define right_height 12
  160. static char right_bits[] = {
  161.    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0xc0, 0x01,
  162.    0x00, 0xc0, 0x07, 0xf0, 0xff, 0x1f, 0xf0, 0xff, 0x1f, 0x00, 0xc0, 0x07,
  163.    0x00, 0xc0, 0x01, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
  164.  
  165. // switch arrow
  166. #define switch_width 24
  167. #define switch_height 12
  168. static char switch_bits[] = {
  169.    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x02, 0x70, 0x00, 0x0e,
  170.    0x7c, 0x00, 0x3e, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7c, 0x00, 0x3e,
  171.    0x70, 0x00, 0x0e, 0x40, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
  172.  
  173. // arrow pointing to the left
  174. #define left_width 24
  175. #define left_height 12
  176. static char left_bits[] = {
  177.    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x80, 0x03, 0x00,
  178.    0xe0, 0x03, 0x00, 0xf8, 0xff, 0x0f, 0xf8, 0xff, 0x0f, 0xe0, 0x03, 0x00,
  179.    0x80, 0x03, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
  180.  
  181.  
  182. static char *thisClassName = "MyColorEditor";
  183.  
  184.  
  185. ////////////////////////////////////////////////////////////////////////
  186. //
  187. // Public constructor - build the widget right now
  188. //
  189. MyColorEditor::MyColorEditor(
  190.     Widget parent,
  191.     const char *name, 
  192.     SbBool buildInsideParent)
  193.     : SoXtComponent(parent, name, buildInsideParent)
  194. //
  195. ////////////////////////////////////////////////////////////////////////
  196. {
  197.     // In this case, this component is what the app wants, so buildNow = TRUE
  198.     constructorCommon(TRUE);
  199. }
  200.  
  201. ////////////////////////////////////////////////////////////////////////
  202. //
  203. // SoEXTENDER constructor - the subclass tells us whether to build or not
  204. //
  205. MyColorEditor::MyColorEditor(
  206.     Widget parent,
  207.     const char *name, 
  208.     SbBool buildInsideParent, 
  209.     SbBool buildNow)
  210.     : SoXtComponent(parent, name, buildInsideParent)
  211. //
  212. ////////////////////////////////////////////////////////////////////////
  213. {
  214.     // In this case, this component may be what the app wants, 
  215.     // or it may want a subclass of this component. Pass along buildNow
  216.     // as it was passed to us.
  217.     constructorCommon(buildNow);
  218. }
  219.  
  220. ////////////////////////////////////////////////////////////////////////
  221. //
  222. // Called by the constructors
  223. //
  224. // private
  225. //
  226. void
  227. MyColorEditor::constructorCommon(SbBool buildNow)
  228. //
  229. //////////////////////////////////////////////////////////////////////
  230. {    
  231.     int i;
  232.     
  233.     // init local vars
  234.     setClassName(thisClassName);
  235.     addVisibilityChangeCallback(visibilityChangeCB, this);
  236.     WYSIWYGmode = FALSE;
  237.     whichSliders = INTENSITY;
  238.     baseRGB[0] = baseRGB[2] = 1.0;
  239.     baseRGB[1] = 0.0;
  240.     baseRGB.getHSVValue(baseHSV);
  241.     acceptButton = slidersForm = NULL;
  242.     mgrWidget = NULL;
  243.     updateFreq = CONTINUOUS;
  244.     
  245.     // copy/paste support
  246.     clipboard = NULL;
  247.     
  248.     // default size
  249.     setSize( SbVec2s(DEFAULT_WIDTH, DEFAULT_HEIGHT) );
  250.     
  251.     // color field vars
  252.     attached = FALSE;
  253.     colorSF = NULL;
  254.     colorMF = NULL;
  255.     editNode = NULL;
  256.     colorSensor = new SoNodeSensor(MyColorEditor::fieldChangedCB, this);
  257.     
  258.     // init callbacks data Ids
  259.     dataId = (ColorEditorCBData *) malloc(sizeof(ColorEditorCBData) * NUM_IDS);
  260.     for (i=0; i<NUM_IDS; i++) {
  261.     dataId[i].id = i;        // since Ids start at 0
  262.     dataId[i].classPtr = this;
  263.     }
  264.     
  265.     // user callbacks
  266.     callbackList = new SoCallbackList;
  267.     ignoreCallback = FALSE;
  268.     
  269.     // NULL out UI components. We'll create them in buildWidget().
  270.     wheel = NULL;
  271.     current = NULL;
  272.     previous = NULL;
  273.     for (i=0; i<6; i++)
  274.     sliders[i] = NULL;
  275.     
  276.     // Build the widget tree, and let SoXtComponent know about our base widget.
  277.     if (buildNow) {
  278.     Widget w = buildWidget(getParentWidget());
  279.     setBaseWidget(w);
  280.     }
  281. }
  282.  
  283.  
  284. ////////////////////////////////////////////////////////////////////////
  285. //
  286. //    Destructor.
  287. //
  288.  
  289. MyColorEditor::~MyColorEditor()
  290. //
  291. ////////////////////////////////////////////////////////////////////////
  292. {
  293.     // detaches itself and remove sensor
  294.     if ( isAttached() )
  295.         detach();
  296.     
  297.     // delete everything
  298.     free(dataId);
  299.     delete clipboard;
  300.     delete callbackList;
  301.     delete wheel;
  302.     delete current;
  303.     delete previous;
  304.     for (int i=0; i<6; i++)
  305.     delete sliders[i];
  306. }
  307.  
  308.  
  309. ////////////////////////////////////////////////////////////////////////
  310. //
  311. //    This routine builds all the widgets, and do the layout using motif.
  312. //
  313. // usage: private
  314. //
  315. Widget
  316. MyColorEditor::buildWidget(Widget parent)
  317. //
  318. ////////////////////////////////////////////////////////////////////////
  319. {
  320.     Widget  menubar;
  321.     int        n;
  322.     Arg     args[12];
  323.     
  324.     //
  325.     // create a top level form to hold everything together
  326.     //
  327.     
  328.     SbVec2s size = getSize();
  329.     n = 0;
  330.     if ((size[0] != 0) && (size[1] != 0)) {
  331.     XtSetArg(args[n], XtNwidth, size[0]); n++;
  332.     XtSetArg(args[n], XtNheight, size[1]); n++;
  333.     }
  334.     
  335.     // create the top level widget, then register it with a class name
  336.     mgrWidget = XtCreateWidget(getWidgetName(), xmFormWidgetClass, parent, args, n);
  337.     registerWidget(mgrWidget);
  338.     
  339.     //
  340.     // build top level components
  341.     //
  342.     menubar = buildPulldownMenu(mgrWidget);
  343.     buttonsForm = buildControls(mgrWidget);
  344.  
  345.     //
  346.     // allocate color wheel
  347.     //
  348.     wheel = new MyColorWheel(mgrWidget);
  349.     wheel->setBaseColor(baseHSV);
  350.     wheel->addValueChangedCallback(&MyColorEditor::wheelCallback, this);
  351.     wheelForm = wheel->getWidget();
  352.  
  353.     slidersForm = buildSlidersForm(mgrWidget);
  354.     
  355.     //
  356.     // layout !
  357.     //
  358.     n = 0;
  359.     XtSetArg(args[n], XmNtopAttachment,     XmATTACH_FORM); n++;
  360.     XtSetArg(args[n], XmNleftAttachment,    XmATTACH_FORM); n++;
  361.     XtSetArg(args[n], XmNrightAttachment,   XmATTACH_POSITION); n++;
  362.     XtSetArg(args[n], XmNrightPosition,     BUTTONS_FORM_RIGHT_POSITION); n++;
  363.     XtSetArg(args[n], XmNbottomAttachment,  XmATTACH_NONE); n++;
  364.     XtSetValues(menubar, args, n);
  365.     
  366.     n = 0;
  367.     XtSetArg(args[n], XmNtopAttachment,     XmATTACH_WIDGET); n++;
  368.     XtSetArg(args[n], XmNtopWidget,         menubar); n++;
  369.     XtSetArg(args[n], XmNleftAttachment,    XmATTACH_FORM); n++;
  370.     XtSetArg(args[n], XmNrightAttachment,   XmATTACH_POSITION); n++;
  371.     XtSetArg(args[n], XmNrightPosition,     BUTTONS_FORM_RIGHT_POSITION); n++;
  372.     // Note: bottom attachment changes dynamically
  373.     XtSetValues(buttonsForm, args, n);
  374.     
  375.     n = 0;
  376.     XtSetArg(args[n], XmNtopAttachment,     XmATTACH_FORM); n++;
  377.     XtSetArg(args[n], XmNrightAttachment,   XmATTACH_FORM); n++;
  378.     XtSetArg(args[n], XmNleftAttachment,    XmATTACH_WIDGET); n++;
  379.     XtSetArg(args[n], XmNleftWidget,         buttonsForm); n++;
  380.     // Note: bottom attachment changes dynamically
  381.     XtSetValues(wheelForm, args, n);
  382.     
  383.     n = 0;
  384.     XtSetArg(args[n], XmNrightAttachment,   XmATTACH_FORM); n++;
  385.     XtSetArg(args[n], XmNrightOffset,       OFFSET); n++;
  386.     XtSetArg(args[n], XmNleftAttachment,    XmATTACH_FORM); n++;
  387.     XtSetArg(args[n], XmNleftOffset,        OFFSET); n++;
  388.     XtSetArg(args[n], XmNbottomAttachment,  XmATTACH_FORM); n++;
  389.     XtSetArg(args[n], XmNbottomOffset,      OFFSET); n++;
  390.     // Note: top attachment changes dynamically
  391.     XtSetValues(slidersForm, args, n);
  392.     
  393.     doDynamicTopLevelLayout();
  394.     
  395.     // manage all widgets
  396.     XtManageChild(menubar);
  397.     XtManageChild(buttonsForm);
  398.     XtManageChild(wheelForm);
  399.     
  400.     
  401.     //
  402.     // get default values from X resource!
  403.     //
  404.     SoXtResource xr(mgrWidget);
  405.     char *val;
  406.     SbBool b;
  407.     
  408.     if (xr.getResource("wysiwyg", "Wysiwyg", b))
  409.      setWYSIWYG(b);
  410.     
  411.     //??? we could get the quark for each string, then get the quark for val,
  412.     //??? and compare quarks - it might be faster.
  413.     // strcasecmp is case insensitive
  414.     if (xr.getResource("colorSliders", "ColorSliders", val)) {
  415.      if      (strcasecmp(val, "none") == 0)  
  416.          setCurrentSliders(NONE);
  417.      else if (strcasecmp(val, "intensity") == 0)  
  418.          setCurrentSliders(INTENSITY);
  419.      else if (strcasecmp(val, "rgb") == 0)  
  420.          setCurrentSliders(RGB);
  421.      else if (strcasecmp(val, "hsv") == 0)  
  422.          setCurrentSliders(HSV);
  423.      else if (strcasecmp(val, "rgb_v") == 0)  
  424.          setCurrentSliders(RGB_V);
  425.      else if (strcasecmp(val, "rgb_hsv") == 0)  
  426.          setCurrentSliders(RGB_HSV);
  427.     }
  428.     
  429.     //??? should the base class do the check for continuous and manual?
  430.     if (xr.getResource("updateFrequency", "UpdateFrequency", val)) {
  431.      if      (strcasecmp(val, "continuous") == 0)  
  432.          setUpdateFrequency(CONTINUOUS);
  433.      else if (strcasecmp(val, "manual") == 0)  
  434.          setUpdateFrequency(AFTER_ACCEPT);
  435.     }
  436.     
  437.     
  438.     return mgrWidget;
  439. }
  440.  
  441.  
  442. ////////////////////////////////////////////////////////////////////////
  443. //
  444. //    builds the pulldown menu
  445. //
  446. // usage: private
  447.  
  448. Widget
  449. MyColorEditor::buildPulldownMenu(Widget parent)
  450. //
  451. ////////////////////////////////////////////////////////////////////////
  452. {
  453.     Widget  menuw[2], sub1w[15], sub2w[15];
  454.     int        num1 = 0, num2 = 0;
  455.     int        i, n;
  456.     Arg     args[2];
  457.     
  458.     //
  459.     // create the pulldown menu
  460.     //
  461.     Widget menubar = XmCreateMenuBar(parent, "menuBar", NULL, 0);
  462.     
  463.     // NOTE: menu items must be created in this order!
  464.     menuItems.truncate(0);
  465.     
  466.     
  467.     //
  468.     // SUBMENU 1
  469.     //
  470.     Widget sub_menu1 = XmCreatePulldownMenu(menubar, NULL, NULL, 0);
  471.     n = 0;
  472.     XtSetArg(args[n], XmNsubMenuId, sub_menu1); n++;
  473.     menuw[0] = XtCreateWidget("Edit", xmCascadeButtonGadgetClass, 
  474.     menubar, args, n);
  475.     
  476.     // CONTINUOUS_ID,
  477.     // MANUAL_ID,
  478.     n = 0;
  479.     XtSetArg(args[n], XmNindicatorType, XmONE_OF_MANY); n++;
  480.     for (i=0; i<2; i++) {
  481.     sub1w[num1] = XtCreateWidget(edit_menu[num1],
  482.         xmToggleButtonGadgetClass, sub_menu1, args, n);
  483.     XtAddCallback(sub1w[num1], XmNvalueChangedCallback, 
  484.         (XtCallbackProc) &MyColorEditor::editMenuCallback, 
  485.         (XtPointer) &dataId[CONTINUOUS_ID+i]);
  486.     menuItems.append(sub1w[num1]);
  487.     num1++;
  488.     }
  489.     
  490.     // SEPARATOR
  491.     sub1w[num1] = XtCreateWidget(edit_menu[num1], xmSeparatorGadgetClass,
  492.     sub_menu1, NULL, 0);
  493.     num1++;
  494.     
  495.     // WYSIWYG_ID
  496.     sub1w[num1] = XtCreateWidget(edit_menu[num1], xmToggleButtonGadgetClass,
  497.         sub_menu1, NULL, 0);
  498.     XtAddCallback(sub1w[num1], XmNvalueChangedCallback, 
  499.     (XtCallbackProc) &MyColorEditor::editMenuCallback, 
  500.     (XtPointer) &dataId[WYSIWYG_ID]);
  501.     menuItems.append(sub1w[num1]);
  502.     num1++;
  503.     
  504.     // SEPARATOR
  505.     sub1w[num1] = XtCreateWidget(edit_menu[num1],
  506.     xmSeparatorGadgetClass, sub_menu1, NULL, 0);
  507.     num1++;
  508.     
  509.     // COPY_ID,
  510.     // PASTE_ID,
  511.     for (i=0; i<2; i++) {
  512.     sub1w[num1] = XtCreateWidget(edit_menu[num1],
  513.         xmPushButtonGadgetClass, sub_menu1, NULL, 0);
  514.     XtAddCallback(sub1w[num1], XmNactivateCallback, 
  515.         (XtCallbackProc) &MyColorEditor::editMenuCallback, 
  516.         (XtPointer) &dataId[COPY_ID+i]);
  517.     num1++;
  518.     // we do not append these to menuItems; since they are push buttons
  519.     // and not toggle buttons, we don't need to save them for future updates
  520.     }
  521.     
  522.     // SEPARATOR
  523.     sub1w[num1] = XtCreateWidget(edit_menu[num1],
  524.     xmSeparatorGadgetClass, sub_menu1, NULL, 0);
  525.     num1++;
  526.     
  527.     // HELP_ID
  528.     sub1w[num1] = XtCreateWidget(edit_menu[num1],
  529.     xmPushButtonGadgetClass, sub_menu1, NULL, 0);
  530.     XtAddCallback(sub1w[num1], XmNactivateCallback, 
  531.     (XtCallbackProc) &MyColorEditor::editMenuCallback, 
  532.     (XtPointer) &dataId[HELP_ID]);
  533.     num1++;
  534.     
  535.     //
  536.     // SUBMENU 2
  537.     //
  538.     Widget sub_menu2 = XmCreatePulldownMenu(menubar, NULL, NULL, 0);
  539.     n = 0;
  540.     XtSetArg(args[n], XmNsubMenuId, sub_menu2); n++;
  541.     menuw[1] = XtCreateWidget("Sliders", xmCascadeButtonGadgetClass, 
  542.         menubar, args, n);
  543.     
  544.     // NONE
  545.     // INTENSITY
  546.     // RGB
  547.     // HSV
  548.     // RGB_V
  549.     // RGB_HSV
  550.     n = 0;
  551.     XtSetArg(args[n], XmNindicatorType, XmONE_OF_MANY); n++;
  552.     for (i=0; i<6; i++) {
  553.     sub2w[num2] = XtCreateWidget(slider_menu[num2],
  554.         xmToggleButtonGadgetClass, sub_menu2, args, n);
  555.     XtAddCallback(sub2w[num2], XmNvalueChangedCallback, 
  556.         (XtCallbackProc) &MyColorEditor::sliderMenuCallback, 
  557.         (XtPointer) &dataId[NONE_SLIDER_ID+i]);
  558.     menuItems.append(sub2w[num2]);
  559.     num2++;
  560.     }
  561.     
  562.     
  563.     // menu display callback so we can change the menu item
  564.     XtAddCallback(sub_menu1, XmNmapCallback,
  565.     (XtCallbackProc) MyColorEditor::menuDisplay, (XtPointer) this);
  566.     XtAddCallback(sub_menu2, XmNmapCallback,
  567.     (XtCallbackProc) MyColorEditor::menuDisplay, (XtPointer) this);
  568.     
  569.     
  570.     // manage all children
  571.     XtManageChildren(sub1w, num1);
  572.     XtManageChildren(sub2w, num2);
  573.     XtManageChildren(menuw, 2);
  574.     
  575.     return menubar;
  576. }
  577.  
  578.  
  579. ////////////////////////////////////////////////////////////////////////
  580. //
  581. //    builds the color swatches, arrow buttons and accept button.
  582. //
  583. // usage: private
  584.  
  585. Widget
  586. MyColorEditor::buildControls(Widget parent)
  587. //
  588. ////////////////////////////////////////////////////////////////////////
  589. {
  590.     Widget  curW, prevW, buttonw[3], patchButForm;
  591.     int        i, n;
  592.     Arg     args[12];
  593.     
  594.     //
  595.     // build the buttons form
  596.     //
  597.     buttonsForm = XtCreateWidget("buttonsForm", xmFormWidgetClass, parent, NULL, 0);
  598.     
  599.     // build swatches
  600.     current = new MyColorPatch(buttonsForm, "Current");
  601.     current->setColor(baseRGB);
  602.     curW = current->getWidget();
  603.     previous = new MyColorPatch(buttonsForm, "Previous");
  604.     previous->setColor(baseRGB);    
  605.     prevW = previous->getWidget();
  606.     
  607.     //
  608.     // create the arrow buttons (use a form to lay them inside)
  609.     //
  610.     patchButForm = XtCreateWidget("patchButForm", xmFormWidgetClass, 
  611.     buttonsForm, NULL, 0);
  612.     n = 0;
  613.     XtSetArg(args[n], XmNhighlightThickness, 0); n++;
  614.     for (i=0; i<3; i++) {
  615.     buttonw[i] = XtCreateWidget(button_names[i], xmPushButtonGadgetClass,
  616.         patchButForm, args, n);
  617.     XtAddCallback(buttonw[i], XmNactivateCallback, 
  618.             (XtCallbackProc) &MyColorEditor::buttonsCallback, 
  619.             (XtPointer) &dataId[SAVE_ID+i]);
  620.     }
  621.     
  622.     //
  623.     // create the pixmaps for the arrow buttons
  624.     //
  625.     Pixmap    pixmaps[3][2];
  626.     Display    *display = XtDisplay(parent);
  627.     Drawable    d = DefaultRootWindow(display);
  628.     Pixel    fg, bg, abg;
  629.     
  630.     // get the color of the push buttons
  631.     // ??? the foregrounf and background color have to be
  632.     // ??? taken from the parent widget because we are using
  633.     // ??? Gadget push buttons (not Widget push buttons)
  634.     n = 0;
  635.     XtSetArg(args[n], XmNforeground, &fg); n++;
  636.     XtSetArg(args[n], XmNbackground, &bg); n++;
  637.     XtGetValues(patchButForm, args, n);
  638.     n = 0;
  639.     XtSetArg(args[n], XmNarmColor, &abg); n++;
  640.     XtGetValues(buttonw[0], args, n);
  641.     
  642.     // create the pixmaps from the bitmap data (depth 1).
  643.     // Two sets of pixmaps are created for when the button is
  644.     // up and down.
  645.     int depth = XDefaultDepthOfScreen(XtScreen(parent));
  646.     pixmaps[0][0] = XCreatePixmapFromBitmapData(display, d, 
  647.     right_bits, right_width, right_height, fg, bg, depth);
  648.     pixmaps[0][1] = XCreatePixmapFromBitmapData(display, d, 
  649.     right_bits, right_width, right_height, fg, abg, depth);
  650.     pixmaps[1][0] = XCreatePixmapFromBitmapData(display, d, 
  651.     switch_bits, switch_width, switch_height, fg, bg, depth);
  652.     pixmaps[1][1] = XCreatePixmapFromBitmapData(display, d, 
  653.     switch_bits, switch_width, switch_height, fg, abg, depth);
  654.     pixmaps[2][0] = XCreatePixmapFromBitmapData(display, d, 
  655.     left_bits, left_width, left_height, fg, bg, depth);
  656.     pixmaps[2][1] = XCreatePixmapFromBitmapData(display, d, 
  657.     left_bits, left_width, left_height, fg, abg, depth);
  658.     
  659.     // assign the pixmaps to the push buttons
  660.     XtSetArg(args[0], XmNlabelType, XmPIXMAP);
  661.     for (i=0; i<3; i++) {
  662.     XtSetArg(args[1], XmNlabelPixmap, pixmaps[i][0]);
  663.     XtSetArg(args[2], XmNarmPixmap, pixmaps[i][1]);
  664.     XtSetValues(buttonw[i], args, 3);
  665.     }
  666.     
  667.     //
  668.     // build the accept button
  669.     //
  670.     n = 0;
  671.     XtSetArg(args[n], XmNhighlightThickness, 0); n++;
  672.     acceptButton = XtCreateWidget("Accept", xmPushButtonGadgetClass, 
  673.         buttonsForm, args, n);
  674.     XtAddCallback(acceptButton, XmNactivateCallback, 
  675.     (XtCallbackProc) &MyColorEditor::buttonsCallback, 
  676.     (XtPointer) &dataId[ACCEPT_ID]);
  677.     
  678.     //
  679.     // layout !
  680.     //
  681.     n = 0;
  682.     XtSetArg(args[n], XmNleftAttachment,    XmATTACH_POSITION); n++;
  683.     XtSetArg(args[n], XmNleftPosition,         10); n++;
  684.     XtSetArg(args[n], XmNrightAttachment,   XmATTACH_POSITION); n++;
  685.     XtSetArg(args[n], XmNrightPosition,     49); n++;
  686.     XtSetArg(args[n], XmNtopAttachment,     XmATTACH_POSITION); n++;
  687.     XtSetArg(args[n], XmNtopPosition,         5); n++;
  688.     XtSetArg(args[n], XmNbottomAttachment,  XmATTACH_POSITION); n++;
  689.     XtSetArg(args[n], XmNbottomPosition,    45); n++;
  690.     XtSetValues(curW, args, n);
  691.     XtSetArg(args[1], XmNleftPosition,         51);
  692.     XtSetArg(args[3], XmNrightPosition,     90);
  693.     XtSetValues(prevW, args, n);
  694.     
  695.     n = 0;
  696.     XtSetArg(args[n], XmNtopAttachment,     XmATTACH_FORM); n++;
  697.     XtSetArg(args[n], XmNbottomAttachment,  XmATTACH_FORM); n++;
  698.     XtSetArg(args[n], XmNleftAttachment,    XmATTACH_POSITION); n++;
  699.     XtSetArg(args[3], XmNleftPosition,         0); n++;
  700.     XtSetArg(args[n], XmNrightAttachment,   XmATTACH_POSITION); n++;
  701.     XtSetArg(args[5], XmNrightPosition,     30); n++;
  702.     XtSetValues(buttonw[0], args, n);
  703.     XtSetArg(args[3], XmNleftPosition,         31);
  704.     XtSetArg(args[5], XmNrightPosition,     69);
  705.     XtSetValues(buttonw[1], args, n);
  706.     XtSetArg(args[3], XmNleftPosition,         70);
  707.     XtSetArg(args[5], XmNrightPosition,     100);
  708.     XtSetValues(buttonw[2], args, n);
  709.     
  710.     n = 0;
  711.     XtSetArg(args[n], XmNtopAttachment,     XmATTACH_WIDGET); n++;
  712.     XtSetArg(args[n], XmNtopWidget,         curW); n++;
  713.     XtSetArg(args[n], XmNleftAttachment,    XmATTACH_OPPOSITE_WIDGET); n++;
  714.     XtSetArg(args[n], XmNleftWidget,         curW); n++;
  715.     XtSetArg(args[n], XmNrightAttachment,   XmATTACH_OPPOSITE_WIDGET); n++;
  716.     XtSetArg(args[n], XmNrightWidget,         prevW); n++;
  717.     XtSetArg(args[n], XmNbottomAttachment,  XmATTACH_NONE); n++;
  718.     XtSetValues(patchButForm, args, n);
  719.     
  720.     int offset = (whichSliders == NONE) ? 0 : OFFSET ;
  721.     n = 0;
  722.     XtSetArg(args[n], XmNleftAttachment,    XmATTACH_POSITION); n++;
  723.     XtSetArg(args[n], XmNleftPosition,         30); n++;
  724.     XtSetArg(args[n], XmNrightAttachment,   XmATTACH_POSITION); n++;
  725.     XtSetArg(args[n], XmNrightPosition,     70); n++;
  726.     XtSetArg(args[n], XmNtopAttachment,     XmATTACH_NONE); n++;
  727.     XtSetArg(args[n], XmNbottomAttachment,  XmATTACH_FORM); n++;
  728.     XtSetArg(args[n], XmNbottomOffset,      offset); n++;
  729.     XtSetValues(acceptButton, args, n);
  730.     
  731.     
  732.     // manage all children
  733.     XtManageChild(curW);
  734.     XtManageChild(prevW);
  735.     XtManageChildren(buttonw, 3);
  736.     XtManageChild(patchButForm);
  737.     if (updateFreq == AFTER_ACCEPT)
  738.         XtManageChild(acceptButton);
  739.     
  740.     return buttonsForm;
  741. }
  742.  
  743.  
  744. ////////////////////////////////////////////////////////////////////////
  745. //
  746. //    builds the sliders form
  747. //
  748. // usage: private
  749.  
  750. Widget
  751. MyColorEditor::buildSlidersForm(Widget parent)
  752. //
  753. ////////////////////////////////////////////////////////////////////////
  754. {
  755.     int        n;
  756.     Arg     args[12];
  757.     
  758.     //
  759.     // build the sliders form
  760.     //
  761.     n = 0;
  762.     XtSetArg(args[n], XmNfractionBase, 1000); n++;
  763.     slidersForm = XtCreateWidget("slidersForm", xmFormWidgetClass, 
  764.     parent, args, n);
  765.     
  766.     // build sliders
  767.     sliders[0] = new MyColorSlider(slidersForm, NULL, TRUE, 
  768.             MyColorSlider::RED_SLIDER);
  769.     sliders[1] = new MyColorSlider(slidersForm, NULL, TRUE, 
  770.             MyColorSlider::GREEN_SLIDER);
  771.     sliders[2] = new MyColorSlider(slidersForm, NULL, TRUE, 
  772.             MyColorSlider::BLUE_SLIDER);
  773.     sliders[3] = new MyColorSlider(slidersForm, NULL, TRUE, 
  774.             MyColorSlider::HUE_SLIDER);
  775.     sliders[4] = new MyColorSlider(slidersForm, NULL, TRUE, 
  776.             MyColorSlider::SATURATION_SLIDER);
  777.     sliders[5] = new MyColorSlider(slidersForm, NULL, TRUE, 
  778.             MyColorSlider::VALUE_SLIDER);
  779.  
  780.     int i;
  781.     for (i=0; i<3; i++)
  782.     sliders[i]->setBaseColor(baseRGB.getValue());
  783.     for (i=3; i<6; i++)
  784.     sliders[i]->setBaseColor(baseHSV);
  785.  
  786.     n = 0;
  787.     XtSetArg(args[n], XmNleftAttachment,    XmATTACH_FORM); n++;
  788.     XtSetArg(args[n], XmNrightAttachment,   XmATTACH_FORM); n++;
  789.     for (i=0; i<6; i++) {
  790.         sliders[i]->setLabel(slider_labels[i]);
  791.     sliders[i]->addValueChangedCallback(
  792.         &MyColorEditor::sliderCallback, 
  793.         &dataId[R_SLIDER_ID+i]);
  794.     XtSetValues(sliders[i]->getWidget(), args, n);
  795.     }
  796.  
  797.     
  798.     //
  799.     // layout !
  800.     //
  801.     doSliderLayout();
  802.     
  803.     return slidersForm;
  804. }
  805.  
  806.  
  807. ////////////////////////////////////////////////////////////////////////
  808. //
  809. //    This routine attaches itself to a single color field.
  810. //
  811. // usage: public
  812.  
  813. void
  814. MyColorEditor::attach(SoSFColor *sf, SoBase *node)
  815. //
  816. ////////////////////////////////////////////////////////////////////////
  817. {
  818.     if ( isAttached() )
  819.         detach();
  820.     
  821.     if (sf != NULL && node != NULL) {
  822.     setColor(sf->getValue());
  823.     colorSF = sf;
  824.     editNode = node;
  825.     editNode->ref();
  826.     colorSensor->attach((SoNode *) editNode);
  827.     attached = TRUE;
  828.     }
  829. }
  830.  
  831.  
  832. ////////////////////////////////////////////////////////////////////////
  833. //
  834. //    This routine attaches itself to a multiple value color field.
  835. //
  836. // usage: public
  837.  
  838. void
  839. MyColorEditor::attach(SoMFColor *mf, int ind, SoBase *node)
  840. //
  841. ////////////////////////////////////////////////////////////////////////
  842. {
  843.     if ( isAttached() )
  844.         detach();
  845.     
  846.     if (mf != NULL && ind >= 0 && node != NULL) {
  847.     setColor((*mf)[ind]);
  848.     colorMF = mf;
  849.     index = ind;
  850.     editNode = node;
  851.     editNode->ref();
  852.     colorSensor->attach((SoNode *) editNode);
  853.     attached = TRUE;
  854.     }
  855. }
  856.  
  857.  
  858. ////////////////////////////////////////////////////////////////////////
  859. //
  860. //    This routine detaches itself from the color field.
  861. //
  862. // usage: public
  863.  
  864. void
  865. MyColorEditor::detach()
  866. //
  867. ////////////////////////////////////////////////////////////////////////
  868. {
  869.     if ( ! isAttached() )
  870.     return;
  871.     
  872.     colorSensor->detach();
  873.     editNode->unref();
  874.     editNode = NULL;
  875.     colorSF = NULL;
  876.     colorMF = NULL;
  877.     attached = FALSE;
  878. }
  879.  
  880.  
  881. ////////////////////////////////////////////////////////////////////////
  882. //
  883. //    This routine sets the current color.
  884. //
  885. // usage: public
  886. //
  887. void
  888. MyColorEditor::setColor(const SbColor &color)
  889. //
  890. ////////////////////////////////////////////////////////////////////////
  891. {
  892.     if (color == baseRGB)
  893.         return;
  894.     
  895.     // save color
  896.     baseRGB = color;
  897.     baseRGB.getHSVValue(baseHSV);
  898.     
  899.     ignoreCallback = TRUE;
  900.     
  901.     // now send the colors to the sliders/color wheel
  902.     for (int i=0; i<3; i++)
  903.         sliders[i]->setBaseColor(baseRGB.getValue());
  904.     for (i=3; i<6; i++)
  905.         sliders[i]->setBaseColor(baseHSV);
  906.     wheel->setBaseColor(baseHSV);
  907.     current->setColor(baseRGB);
  908.     
  909.     ignoreCallback = FALSE;
  910.     
  911.     if (updateFreq == CONTINUOUS)
  912.     doUpdates();
  913. }
  914.  
  915.  
  916. ////////////////////////////////////////////////////////////////////////
  917. //
  918. //    This routine sets the WYSIWYG mode.
  919. //
  920. // usage: public
  921.  
  922. void
  923. MyColorEditor::setWYSIWYG(SbBool flag)
  924. //
  925. ////////////////////////////////////////////////////////////////////////
  926. {
  927.     if (WYSIWYGmode == flag)
  928.         return;
  929.     
  930.     WYSIWYGmode = flag;
  931.     
  932.     // now update the sliders and color wheel
  933.     for (int i=0; i<6; i++)
  934.     sliders[i]->setWYSIWYG(WYSIWYGmode);
  935.     wheel->setWYSIWYG(WYSIWYGmode);
  936. }
  937.  
  938.  
  939. ////////////////////////////////////////////////////////////////////////
  940. //
  941. //    This routine sets the update frequency.
  942. //
  943. // usage: virtual public
  944. //
  945. void
  946. MyColorEditor::setUpdateFrequency(MyColorEditor::UpdateFrequency freq)
  947. //
  948. ////////////////////////////////////////////////////////////////////////
  949. {
  950.     if (updateFreq == freq)
  951.     return;
  952.     
  953.     updateFreq = freq;
  954.     
  955.     // show/hide the accept button
  956.     if (acceptButton != NULL) {
  957.     if (updateFreq == CONTINUOUS)
  958.         XtUnmanageChild(acceptButton);
  959.     else
  960.         XtManageChild(acceptButton);
  961.     }
  962.     
  963.     // update the attached node if we switch to continous
  964.     if (updateFreq == CONTINUOUS)
  965.         doUpdates();
  966. }
  967.  
  968.  
  969. ////////////////////////////////////////////////////////////////////////
  970. //
  971. //    This routine specifies which sliders are being displayed.
  972. //
  973. // usage: public
  974.  
  975. void
  976. MyColorEditor::setCurrentSliders(MyColorEditor::Sliders id)
  977. //
  978. ////////////////////////////////////////////////////////////////////////
  979. {
  980.     int i, prevNum, curNum;
  981.     
  982.     if (whichSliders == id)
  983.         return;
  984.     
  985.     prevNum = numberOfSliders(whichSliders);
  986.     curNum = numberOfSliders(id);
  987.     
  988.     // check to make sure widget has been built, otherwise just change the
  989.     // default window size.
  990.     if (mgrWidget == NULL) {
  991.     // set new height
  992.     SbVec2s size = getSize();
  993.     float r = (TOP_REGION_SIZE + curNum) / float(TOP_REGION_SIZE + prevNum);
  994.     size[1] = short(size[1] * r);
  995.     setSize(size);
  996.         whichSliders = id;
  997.     return;
  998.     }
  999.     
  1000.     //
  1001.     // hide the current set of sliders
  1002.     //
  1003.     switch(whichSliders) {
  1004.         case NONE:
  1005.         break;
  1006.         case INTENSITY:
  1007.         sliders[5]->hide();
  1008.         break;
  1009.     case RGB:
  1010.         for (i=0; i<3; i++)
  1011.         sliders[i]->hide();
  1012.         break;
  1013.     case HSV:
  1014.         for (i=3; i<6; i++)
  1015.         sliders[i]->hide();
  1016.         break;
  1017.     case RGB_V:
  1018.         for (i=0; i<3; i++)
  1019.         sliders[i]->hide();
  1020.         sliders[5]->hide();
  1021.         break;
  1022.     case RGB_HSV:
  1023.         for (i=0; i<6; i++)
  1024.         sliders[i]->hide();
  1025.         break;
  1026.     }
  1027.     
  1028.     //
  1029.     // check if window needs to be resized
  1030.     //
  1031.     Widget parent = XtParent(mgrWidget);
  1032.     if (XtIsShell(parent) && curNum != prevNum) {
  1033.         
  1034.     // get current window height and find new height
  1035.     SbVec2s size = getSize();
  1036.     float r = (TOP_REGION_SIZE + curNum) / float(TOP_REGION_SIZE + prevNum);
  1037.     size[1] = short(size[1] * r);
  1038.     SoXt::setWidgetSize(parent, size);
  1039.     }
  1040.     
  1041.     // finally do new layout
  1042.     whichSliders = id;
  1043.     doDynamicTopLevelLayout();
  1044.     doSliderLayout();
  1045. }
  1046.  
  1047.  
  1048. ////////////////////////////////////////////////////////////////////////
  1049. //
  1050. //    routine to lay sliders out within the slider form.
  1051. //
  1052. // usage: protected
  1053.  
  1054. void
  1055. MyColorEditor::doSliderLayout()
  1056. //
  1057. ////////////////////////////////////////////////////////////////////////
  1058. {
  1059.     int i, n;
  1060.     Arg args[4];
  1061.     
  1062.     ignoreCallback = TRUE;
  1063.     
  1064.     switch(whichSliders) {
  1065.         case NONE:
  1066.         break;
  1067.     
  1068.         case INTENSITY:
  1069.         n = 0;
  1070.         XtSetArg(args[n], XmNtopAttachment,         XmATTACH_FORM); n++;
  1071.         XtSetArg(args[n], XmNbottomAttachment,      XmATTACH_POSITION); n++;
  1072.         XtSetArg(args[n], XmNbottomPosition,        990); n++;
  1073.         XtSetValues(sliders[5]->getWidget(), args, n);
  1074.         sliders[5]->setBaseColor(baseHSV);
  1075.         sliders[5]->show();
  1076.         break;
  1077.         
  1078.     case RGB:
  1079.         for (i=0; i<3; i++) {
  1080.         n = 0;
  1081.         XtSetArg(args[n], XmNtopAttachment,     XmATTACH_POSITION); n++;
  1082.         XtSetArg(args[n], XmNtopPosition,       int((i*1000)/3.0)); n++;
  1083.         XtSetArg(args[n], XmNbottomAttachment,     XmATTACH_POSITION); n++;
  1084.         XtSetArg(args[n], XmNbottomPosition,     int(((i+1)*1000)/3.0) - 10); n++;
  1085.         XtSetValues(sliders[i]->getWidget(), args, n);
  1086.             sliders[i]->setBaseColor(baseRGB.getValue());
  1087.         sliders[i]->show();
  1088.         }
  1089.         break;
  1090.         
  1091.     case HSV:
  1092.         for (i=3; i<6; i++) {
  1093.         n = 0;
  1094.         XtSetArg(args[n], XmNtopAttachment,     XmATTACH_POSITION); n++;
  1095.         XtSetArg(args[n], XmNtopPosition,       int(((i-3)*1000)/3.0)); n++;
  1096.         XtSetArg(args[n], XmNbottomAttachment,     XmATTACH_POSITION); n++;
  1097.         XtSetArg(args[n], XmNbottomPosition,     int(((i-2)*1000)/3.0) - 10); n++;
  1098.         XtSetValues(sliders[i]->getWidget(), args, n);
  1099.             sliders[i]->setBaseColor(baseHSV);
  1100.         sliders[i]->show();
  1101.         }
  1102.         break;
  1103.         
  1104.     case RGB_V:
  1105.         for (i=0; i<4; i++) {
  1106.         n = 0;
  1107.         XtSetArg(args[n], XmNtopAttachment,     XmATTACH_POSITION); n++;
  1108.         XtSetArg(args[n], XmNtopPosition,       i*250); n++;
  1109.         XtSetArg(args[n], XmNbottomAttachment,     XmATTACH_POSITION); n++;
  1110.         XtSetArg(args[n], XmNbottomPosition,     (i+1)*250 - 10); n++;
  1111.         if (i==3) {
  1112.             XtSetValues(sliders[5]->getWidget(), args, n);
  1113.                 sliders[5]->setBaseColor(baseHSV);
  1114.             sliders[5]->show();
  1115.         }
  1116.         else {
  1117.             XtSetValues(sliders[i]->getWidget(), args, n);
  1118.                 sliders[i]->setBaseColor(baseRGB.getValue());
  1119.             sliders[i]->show();
  1120.         }
  1121.         }
  1122.         break;
  1123.         
  1124.     case RGB_HSV:
  1125.         for (i=0; i<6; i++) {
  1126.         n = 0;
  1127.         XtSetArg(args[n], XmNtopAttachment,     XmATTACH_POSITION); n++;
  1128.         XtSetArg(args[n], XmNtopPosition,       int((i*1000)/6.0)); n++;
  1129.         XtSetArg(args[n], XmNbottomAttachment,     XmATTACH_POSITION); n++;
  1130.         XtSetArg(args[n], XmNbottomPosition,     int(((i+1)*1000)/6.0) - 10); n++;
  1131.         XtSetValues(sliders[i]->getWidget(), args, n);
  1132.         if (i > 2)
  1133.                 sliders[i]->setBaseColor(baseHSV);
  1134.         else 
  1135.                 sliders[i]->setBaseColor(baseRGB.getValue());
  1136.         sliders[i]->show();
  1137.         }
  1138.         break;
  1139.     }
  1140.     
  1141.     ignoreCallback = FALSE;
  1142. }
  1143.  
  1144.  
  1145. ////////////////////////////////////////////////////////////////////////
  1146. //
  1147. // routine which does the top level forms layout (slider form, button form
  1148. // and colorWheel) which changes dynamically as the number of sliders changes.
  1149. //
  1150. // usage: private
  1151.  
  1152. void
  1153. MyColorEditor::doDynamicTopLevelLayout()
  1154. //
  1155. ////////////////////////////////////////////////////////////////////////
  1156. {
  1157.     int n, num = numberOfSliders(whichSliders);
  1158.     Arg args[4];
  1159.     
  1160.     if (num) {
  1161.         // calculate the sliders form top position based on how many sliders there are
  1162.     float top = 100 * TOP_REGION_SIZE / float(TOP_REGION_SIZE + num);
  1163.     n = 0;
  1164.     XtSetArg(args[n], XmNtopAttachment,     XmATTACH_POSITION); n++;
  1165.     XtSetArg(args[n], XmNtopPosition,       int(top)); n++;
  1166.     XtSetValues(slidersForm, args, n);
  1167.     
  1168.     if (! XtIsManaged(slidersForm))
  1169.         XtManageChild(slidersForm);
  1170.     
  1171.     n = 0;
  1172.     XtSetArg(args[n], XmNbottomAttachment,     XmATTACH_WIDGET); n++;
  1173.     XtSetArg(args[n], XmNbottomWidget,      slidersForm); n++;
  1174.     XtSetArg(args[n], XmNbottomOffset,      OFFSET); n++;
  1175.     XtSetValues(buttonsForm, args, n);
  1176.     XtSetValues(wheelForm, args, n);
  1177.     
  1178.     n = 0;
  1179.     XtSetArg(args[n], XmNbottomOffset,      0); n++;
  1180.     XtSetValues(acceptButton, args, n);
  1181.     }
  1182.     else {
  1183.     // no sliders so don't use the slidersForm at all
  1184.     n = 0;
  1185.     XtSetArg(args[n], XmNbottomAttachment,     XmATTACH_FORM); n++;
  1186.     XtSetArg(args[n], XmNbottomOffset,      0); n++;
  1187.     XtSetValues(buttonsForm, args, n);
  1188.     XtSetValues(wheelForm, args, n);
  1189.     
  1190.     if (XtIsManaged(slidersForm))
  1191.         XtUnmanageChild(slidersForm);
  1192.     
  1193.     n = 0;
  1194.     XtSetArg(args[n], XmNbottomOffset,      OFFSET); n++;
  1195.     XtSetValues(acceptButton, args, n);
  1196.     }
  1197. }
  1198.  
  1199. ////////////////////////////////////////////////////////////////////////
  1200. //
  1201. //    This routine is called (by fieldChangedCB) when the color field 
  1202. //    has changed value.
  1203. //
  1204. // usage: protected
  1205.  
  1206. void
  1207. MyColorEditor::fieldChanged()
  1208. //
  1209. ////////////////////////////////////////////////////////////////////////
  1210. {
  1211.     if (colorSF != NULL)
  1212.         setColor(colorSF->getValue());
  1213.     else
  1214.         setColor((*colorMF)[index]);
  1215. }
  1216.  
  1217. ////////////////////////////////////////////////////////////////////////
  1218. //
  1219. //    Called when the color wheel changes the current color.
  1220. //
  1221. // usage: private
  1222. //
  1223. void
  1224. MyColorEditor::wheelChanged(const float hsv[3])
  1225. //
  1226. ////////////////////////////////////////////////////////////////////////
  1227. {
  1228.     int i;
  1229.     
  1230.     // wheel can only change hue and saturation
  1231.     baseHSV[0] = hsv[0];
  1232.     baseHSV[1] = hsv[1];
  1233.     baseRGB.setHSVValue(baseHSV);
  1234.     
  1235.     ignoreCallback = TRUE;
  1236.     
  1237.     switch(whichSliders) {
  1238.         case NONE:
  1239.         break;
  1240.     case INTENSITY:
  1241.         sliders[5]->setBaseColor(baseHSV);
  1242.         break;
  1243.     case RGB:
  1244.     case RGB_V:
  1245.         for (i=0; i<3; i++)
  1246.             sliders[i]->setBaseColor(baseRGB.getValue());
  1247.         if (whichSliders == RGB_V)
  1248.             sliders[5]->setBaseColor(baseHSV);
  1249.         break;
  1250.     case HSV:
  1251.         for (i=3; i<6; i++)
  1252.             sliders[i]->setBaseColor(baseHSV);
  1253.         break;
  1254.     case RGB_HSV:
  1255.         for (i=0; i<3; i++)
  1256.             sliders[i]->setBaseColor(baseRGB.getValue());
  1257.         for (i=3; i<6; i++)
  1258.             sliders[i]->setBaseColor(baseHSV);
  1259.         break;
  1260.     }
  1261.     current->setColor(baseRGB);
  1262.     
  1263.     ignoreCallback = FALSE;
  1264.     
  1265.     if (updateFreq == CONTINUOUS)
  1266.     doUpdates();
  1267. }
  1268.  
  1269.  
  1270. ////////////////////////////////////////////////////////////////////////
  1271. //
  1272. //    This routine is called when the sliders changes the current color. 
  1273. //
  1274. // usage: private
  1275. //
  1276. void
  1277. MyColorEditor::sliderChanged(short id, float value)
  1278. //
  1279. ////////////////////////////////////////////////////////////////////////
  1280. {
  1281.     int i;
  1282.     
  1283.     ignoreCallback = TRUE;
  1284.     
  1285.     switch(id) {
  1286.     case R_SLIDER_ID:
  1287.     case G_SLIDER_ID:
  1288.     case B_SLIDER_ID:
  1289.         baseRGB[id - R_SLIDER_ID] = value;
  1290.         baseRGB.getHSVValue(baseHSV);
  1291.         
  1292.         for (i=0; i<3; i++)
  1293.         if (i != id) 
  1294.             sliders[i]->setBaseColor(baseRGB.getValue());
  1295.             
  1296.         if (whichSliders == RGB_V)
  1297.         sliders[5]->setBaseColor(baseHSV);
  1298.         else if (whichSliders == RGB_HSV)
  1299.             for (i=3; i<6; i++)
  1300.             sliders[i]->setBaseColor(baseHSV);
  1301.         wheel->setBaseColor(baseHSV);
  1302.         current->setColor(baseRGB);
  1303.         break;
  1304.         
  1305.     case H_SLIDER_ID:
  1306.     case S_SLIDER_ID:
  1307.     case V_SLIDER_ID:
  1308.         baseHSV[id - H_SLIDER_ID] = value;
  1309.         baseRGB.setHSVValue(baseHSV);
  1310.         
  1311.         switch (whichSliders) {
  1312.             case HSV:
  1313.         case RGB_HSV:
  1314.             for (i=3; i<6; i++)
  1315.             if (i != id) sliders[i]->setBaseColor(baseHSV);
  1316.             if (whichSliders == RGB_HSV)
  1317.             for (i=0; i<3; i++)
  1318.                 sliders[i]->setBaseColor(baseRGB.getValue());
  1319.             break;
  1320.         case RGB_V:
  1321.             for (i=0; i<3; i++)
  1322.             sliders[i]->setBaseColor(baseRGB.getValue());
  1323.             break;
  1324.         case INTENSITY:
  1325.             break;
  1326.         case RGB: // not possible cases
  1327.         case NONE:
  1328. #ifdef DEBUG
  1329.             SoDebugError::post("MyColorEditor::sliderChanged",
  1330.             "inconsitant state %d", id);
  1331. #endif
  1332.             break;
  1333.         }
  1334.         wheel->setBaseColor(baseHSV);
  1335.         current->setColor(baseRGB);
  1336.         break;
  1337.      
  1338.     default:
  1339. #ifdef DEBUG   
  1340.         SoDebugError::post("MyColorEditor::sliderChanged",
  1341.             "bad id %d",id);
  1342. #endif
  1343.         break;
  1344.     }
  1345.     
  1346.     ignoreCallback = FALSE;
  1347.     
  1348.     if (updateFreq == CONTINUOUS)
  1349.     doUpdates();
  1350. }
  1351.  
  1352.  
  1353. ////////////////////////////////////////////////////////////////////////
  1354. //
  1355. //    This routine is called when the motif buttons are being pressed.
  1356. //
  1357. // usage: protected
  1358.  
  1359. void
  1360. MyColorEditor::buttonPressed(short id)
  1361. //
  1362. ////////////////////////////////////////////////////////////////////////
  1363. {
  1364.     SbColor col;
  1365.     
  1366.     switch(id) {
  1367.     case SAVE_ID:
  1368.         previous->setColor(baseRGB);
  1369.         break;
  1370.         
  1371.     case SWAP_ID:
  1372.     case RESTORE_ID:
  1373.         col = previous->getColor();
  1374.         
  1375.         if (id == SWAP_ID)
  1376.         previous->setColor(baseRGB);
  1377.         
  1378.         // assign new color
  1379.         setColor(col);
  1380.         
  1381.         if (updateFreq != AFTER_ACCEPT)
  1382.             doUpdates();
  1383.         break;
  1384.         
  1385.     case ACCEPT_ID:
  1386.         doUpdates();
  1387.         break;
  1388.     }
  1389. }
  1390.  
  1391.  
  1392. ////////////////////////////////////////////////////////////////////////
  1393. //
  1394. //    Do the updates - if node is attached, update it; if callback exists,
  1395. //  call it.
  1396. //
  1397. // usage: private
  1398. //
  1399. void
  1400. MyColorEditor::doUpdates()
  1401. //
  1402. ////////////////////////////////////////////////////////////////////////
  1403. {
  1404.     // check for field update
  1405.     if (attached) {
  1406.     if (colorSF != NULL) {
  1407.         colorSF->setValue(baseRGB);
  1408.         if ( colorSF->isIgnored() )
  1409.         colorSF->setIgnored( FALSE );
  1410.     }
  1411.     else {
  1412.         colorMF->set1Value(index, baseRGB);
  1413.         if ( colorMF->isIgnored() )
  1414.         colorMF->setIgnored( FALSE );
  1415.     }
  1416.     }
  1417.     
  1418.     // check for callback
  1419.     void *hackage = (void *) &baseRGB;
  1420.     callbackList->invokeCallbacks(hackage);
  1421. }
  1422.  
  1423. ////////////////////////////////////////////////////////////////////////
  1424. //
  1425. // convenience routine which returns the number of sliders, given 
  1426. // MyColorEditorSliders id.
  1427. //
  1428. // usage: private
  1429.  
  1430. int
  1431. MyColorEditor::numberOfSliders(MyColorEditor::Sliders id)
  1432. //
  1433. ////////////////////////////////////////////////////////////////////////
  1434. {
  1435.     switch(id) {
  1436.     case NONE:
  1437.         return 0;
  1438.     case INTENSITY:
  1439.         return 1;
  1440.     case RGB:
  1441.     case HSV:
  1442.         return 3;
  1443.     case RGB_V:
  1444.         return 4;
  1445.     case RGB_HSV:
  1446.         return 6;
  1447.     }
  1448. }
  1449.  
  1450.  
  1451. ////////////////////////////////////////////////////////////////////////
  1452. //
  1453. //  Copy the current color onto the clipboard.
  1454. //
  1455. //  Use: private
  1456. //
  1457. void
  1458. MyColorEditor::copy(Time eventTime)
  1459. //
  1460. ////////////////////////////////////////////////////////////////////////
  1461. {
  1462. #ifdef DEBUG
  1463.     if (mgrWidget == NULL) {
  1464.     SoDebugError::post("MyColorEditor::copy", "widget is NULL\n");
  1465.     return;
  1466.     }
  1467. #endif
  1468.  
  1469.     if (clipboard == NULL)
  1470.         clipboard = new SoXtClipboard(mgrWidget);
  1471.     
  1472.     // copy the current color using a BaseColor node
  1473.     SoBaseColor *color = new SoBaseColor;
  1474.     color->ref();
  1475.     color->rgb.setValue(baseRGB);
  1476.     clipboard->copy(color, eventTime);
  1477.     color->unref();
  1478. }
  1479.  
  1480. ////////////////////////////////////////////////////////////////////////
  1481. //
  1482. //  Retrieve the selection from the X server and paste it when it
  1483. //  arrives (in our pasteDone callback).
  1484. //
  1485. //  Use: private
  1486. //
  1487. void
  1488. MyColorEditor::paste(Time eventTime)
  1489. //
  1490. ////////////////////////////////////////////////////////////////////////
  1491. {
  1492. #ifdef DEBUG
  1493.     if (mgrWidget == NULL) {
  1494.     SoDebugError::post("MyColorEditor::paste",
  1495.         "widget is NULL\n");
  1496.     return;
  1497.     }
  1498. #endif
  1499.  
  1500.     if (clipboard == NULL)
  1501.         clipboard = new SoXtClipboard(mgrWidget);
  1502.  
  1503.     clipboard->paste(eventTime, MyColorEditor::pasteDoneCB, this);
  1504. }
  1505.  
  1506. ////////////////////////////////////////////////////////////////////////
  1507. //
  1508. //  The X server has finished getting the selection data, and the
  1509. //  paste is complete. Look through the paste data for a base color node.
  1510. //
  1511. //  Use: private
  1512. //
  1513. void
  1514. MyColorEditor::pasteDone(SoPathList *pathList)
  1515. //
  1516. ////////////////////////////////////////////////////////////////////////
  1517. {
  1518.     SoSearchAction sa;
  1519.     SoFullPath *fullPath = NULL;
  1520.     
  1521.     
  1522.     //
  1523.     // search for first base color node in that pasted scene
  1524.     //
  1525.     sa.setType(SoBaseColor::getClassTypeId());
  1526.     for (int i=0; i < pathList->getLength(); i++) {
  1527.     sa.apply( (*pathList)[i] );
  1528.     if ( (fullPath = (SoFullPath *) sa.getPath()) != NULL) {
  1529.         
  1530.         // assign new color
  1531.         SoBaseColor *newColor = (SoBaseColor *) fullPath->getTail();
  1532.         setColor((newColor->rgb)[0]);
  1533.         
  1534.         break;
  1535.     }
  1536.     }
  1537.     
  1538.     //
  1539.     // else search for the first material and extract a color from it
  1540.     // (the diffuse color, which is better than doing nothing)
  1541.     //
  1542.     if (fullPath == NULL) {
  1543.     sa.setType(SoMaterial::getClassTypeId());
  1544.     for (int i=0; i < pathList->getLength(); i++) {
  1545.         sa.apply( (*pathList)[i] );
  1546.         if ( (fullPath = (SoFullPath *) sa.getPath()) != NULL) {
  1547.         
  1548.         SoMaterial *mat = (SoMaterial *) fullPath->getTail();
  1549.         setColor(mat->diffuseColor[0].getValue());
  1550.         
  1551.         break;
  1552.         }
  1553.     }
  1554.     }
  1555.     
  1556.     // ??? We delete the callback data when done with it.
  1557.     delete pathList;
  1558. }
  1559.  
  1560. ////////////////////////////////////////////////////////////////////////
  1561. //
  1562. //  Called by Xt when a menu is about to be displayed.
  1563. //  This gives us a chance to update any items in the menu.
  1564. //
  1565. //  Use: static private
  1566. //
  1567. void
  1568. MyColorEditor::menuDisplay(Widget, MyColorEditor *editor, XtPointer)
  1569. //
  1570. ////////////////////////////////////////////////////////////////////////
  1571. {
  1572.     // turn them all off
  1573.     for (int i = 0; i < NUM_TOGGLES; i++)
  1574.     TOGGLE_OFF(editor->menuItems[i]);
  1575.     
  1576.     // set default toggles
  1577.     switch (editor->updateFreq) {
  1578.     case CONTINUOUS:    TOGGLE_ON(editor->menuItems[CONTINUOUS_TOGGLE]);    break;
  1579.     case AFTER_ACCEPT:  TOGGLE_ON(editor->menuItems[ACCEPT_TOGGLE]);      break;
  1580.     }
  1581.     
  1582.     if (editor->WYSIWYGmode)
  1583.     TOGGLE_ON(editor->menuItems[WYSIWYG_TOGGLE]);
  1584.     
  1585.     switch (editor->whichSliders) {
  1586.     case NONE:      TOGGLE_ON(editor->menuItems[NONE_TOGGLE]);    break;
  1587.     case INTENSITY: TOGGLE_ON(editor->menuItems[INTENSITY_TOGGLE]);    break;
  1588.     case RGB:       TOGGLE_ON(editor->menuItems[RGB_TOGGLE]);     break;
  1589.     case HSV:       TOGGLE_ON(editor->menuItems[HSV_TOGGLE]);     break;
  1590.     case RGB_V:      TOGGLE_ON(editor->menuItems[RGB_V_TOGGLE]);    break;
  1591.     case RGB_HSV:    TOGGLE_ON(editor->menuItems[RGB_HSV_TOGGLE]);    break;
  1592.     }
  1593. }
  1594.  
  1595. //
  1596. // redefine those generic virtual functions
  1597. //
  1598. const char *
  1599. MyColorEditor::getDefaultWidgetName() const
  1600. { return thisClassName; }
  1601.  
  1602. const char *
  1603. MyColorEditor::getDefaultTitle() const
  1604. { return "Color Editor"; }
  1605.  
  1606. const char *
  1607. MyColorEditor::getDefaultIconTitle() const
  1608. { return "Color Editor"; }
  1609.  
  1610.  
  1611.  
  1612.  
  1613. //
  1614. ////////////////////////////////////////////////////////////////////////
  1615. // static callbacks stubs
  1616. ////////////////////////////////////////////////////////////////////////
  1617. //
  1618.  
  1619.  
  1620. //
  1621. // called whenever the component becomes visibble or not
  1622. //
  1623. void
  1624. MyColorEditor::visibilityChangeCB(void *pt, SbBool visible)
  1625. //
  1626. {
  1627.     MyColorEditor *p = (MyColorEditor *)pt;
  1628.     
  1629.     if (visible) {
  1630.     // attach sensor to top node for redrawing purpose
  1631.     if ( p->editNode != NULL && p->colorSensor->getAttachedNode() == NULL)
  1632.         p->colorSensor->attach((SoNode *) p->editNode);
  1633.     }
  1634.     else
  1635.     // detach sensor
  1636.     p->colorSensor->detach();
  1637. }
  1638.  
  1639. void 
  1640. MyColorEditor::wheelCallback(void *p, const float hsv[3])
  1641. {
  1642.     MyColorEditor *c = (MyColorEditor *)p;
  1643.     
  1644.     if (c->ignoreCallback)
  1645.         return;
  1646.     c->wheelChanged(hsv);
  1647. }
  1648.  
  1649. void 
  1650. MyColorEditor::sliderCallback(void *p, float value)
  1651. {
  1652.     ColorEditorCBData *d = (ColorEditorCBData *)p;
  1653.     
  1654.     if (d->classPtr->ignoreCallback)
  1655.         return;
  1656.     d->classPtr->sliderChanged(d->id, value);
  1657. }
  1658.  
  1659. void 
  1660. MyColorEditor::buttonsCallback(Widget, ColorEditorCBData *d, XtPointer)
  1661. { d->classPtr->buttonPressed(d->id); }
  1662.  
  1663. void
  1664. MyColorEditor::fieldChangedCB(void *pt, SoSensor *)
  1665. {
  1666.     MyColorEditor *p = (MyColorEditor *)pt;
  1667.     if (!p->isVisible())
  1668.     return;
  1669.     
  1670.     p->fieldChanged(); 
  1671. }
  1672.  
  1673. void 
  1674. MyColorEditor::editMenuCallback(
  1675.     Widget, ColorEditorCBData *d, XmAnyCallbackStruct *cb)
  1676. {
  1677.     Time eventTime = cb->event->xbutton.time;
  1678.  
  1679.     switch(d->id) {
  1680.     case CONTINUOUS_ID: d->classPtr->setUpdateFrequency(CONTINUOUS);    break;
  1681.     case MANUAL_ID:        d->classPtr->setUpdateFrequency(AFTER_ACCEPT);  break;
  1682.     case WYSIWYG_ID:    d->classPtr->setWYSIWYG( // toggle
  1683.                                 ! d->classPtr->WYSIWYGmode); break;
  1684.         case COPY_ID:        d->classPtr->copy(eventTime); break;
  1685.         case PASTE_ID:        d->classPtr->paste(eventTime); break;
  1686.     case HELP_ID:        d->classPtr->openHelpCard("MyColorEditor.help"); break;
  1687.     }
  1688. }
  1689.  
  1690. void 
  1691. MyColorEditor::sliderMenuCallback(Widget, ColorEditorCBData *d, XtPointer)
  1692. {
  1693.     switch(d->id) {
  1694.         case NONE_SLIDER_ID:          d->classPtr->setCurrentSliders(NONE);            break;
  1695.         case INTENSITY_SLIDER_ID:   d->classPtr->setCurrentSliders(INTENSITY);    break;
  1696.     case RGB_SLIDERS_ID:        d->classPtr->setCurrentSliders(RGB);        break;
  1697.     case HSV_SLIDERS_ID:        d->classPtr->setCurrentSliders(HSV);        break;
  1698.     case RGB_V_SLIDERS_ID:        d->classPtr->setCurrentSliders(RGB_V);        break;
  1699.     case RGB_HSV_SLIDERS_ID:    d->classPtr->setCurrentSliders(RGB_HSV);      break;
  1700.     }
  1701. }
  1702.  
  1703. void 
  1704. MyColorEditor::pasteDoneCB(void *userData, SoPathList *pathList)
  1705. {
  1706.     ((MyColorEditor *) userData)->pasteDone(pathList);
  1707. }
  1708.           
  1709.